home *** CD-ROM | disk | FTP | other *** search
- {*********************************************************}
- {* ValidateNumber *}
- {* Copyright (c) Julian M Bucknall 2001 *}
- {* All rights reserved. *}
- {*********************************************************}
- {* Algorithms Alfresco: Validate a number with an NFA *}
- {*********************************************************}
-
- {Note: this unit is released as freeware. In other words, you are free
- to use this unit in your own applications, however I retain all
- copyright to the code. JMB}
-
- program ValidateNumber;
-
- {$APPTYPE CONSOLE}
-
- uses
- SysUtils;
-
- function NFAValidateNumber(const S : string) : boolean;
- const
- Digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
- type
- TState = (StartScanning, {state A in figure}
- ScannedSign, {state B in figure}
- ScanInteger, {state C in figure}
- ScanLeadDigits, {state D in figure}
- ScannedDecPoint, {state E in figure}
- ScanLeadDecPoint, {state F in figure}
- ScanDecimalDigits); {state G in figure}
- TChoice = packed record
- chInx : integer;
- chMove : integer;
- chState : TState;
- end;
- var
- i : integer;
- State : TState;
- Ch : char;
- Move : integer;
- ChoiceStack : array [0..9] of TChoice;
- ChoiceSP : integer;
- begin
- {assume the number is invalid}
- Result := false;
- {initialize the choice stack}
- ChoiceSP := 0;
- {prepare for scanning}
- Move := 0;
- i := 1;
- State := StartScanning;
- while i <= length(S) do begin
- Ch := S[i];
- case State of
- StartScanning :
- begin
- case Move of
- 0 :
- begin
- if (Ch = '+') then begin
- with ChoiceStack[ChoiceSP] do begin
- chInx := i;
- chMove := Move;
- chState := State;
- end;
- inc(ChoiceSP);
- State := ScannedSign;
- Move := 0;
- inc(i);
- end
- else
- inc(Move);
- end;
- 1 :
- begin
- if (Ch = '-') then begin
- with ChoiceStack[ChoiceSP] do begin
- chInx := i;
- chMove := Move;
- chState := State;
- end;
- inc(ChoiceSP);
- State := ScannedSign;
- Move := 0;
- inc(i);
- end
- else
- inc(Move);
- end;
- 2 :
- begin
- with ChoiceStack[ChoiceSP] do begin
- chInx := i;
- chMove := Move;
- chState := State;
- end;
- inc(ChoiceSP);
- State := ScannedSign;
- Move := 0;
- end;
- else
- if (ChoiceSP = 0) then
- Exit; // error
- dec(ChoiceSP);
- with ChoiceStack[ChoiceSP] do begin
- i := chInx;
- Move := succ(chMove);
- State := chState;
- end;
- end;{Move case}
- end;
- ScannedSign :
- begin
- case Move of
- 0 :
- begin
- if (Ch in Digits) then begin
- with ChoiceStack[ChoiceSP] do begin
- chInx := i;
- chMove := Move;
- chState := State;
- end;
- inc(ChoiceSP);
- State := ScanInteger;
- Move := 0;
- inc(i);
- end
- else
- inc(Move);
- end;
- 1 :
- begin
- if (Ch in Digits) then begin
- with ChoiceStack[ChoiceSP] do begin
- chInx := i;
- chMove := Move;
- chState := State;
- end;
- inc(ChoiceSP);
- State := ScanLeadDigits;
- Move := 0;
- inc(i);
- end
- else
- inc(Move);
- end;
- 2 :
- begin
- if (Ch = DecimalSeparator) then begin
- with ChoiceStack[ChoiceSP] do begin
- chInx := i;
- chMove := Move;
- chState := State;
- end;
- inc(ChoiceSP);
- State := ScanLeadDecPoint;
- Move := 0;
- inc(i);
- end
- else
- inc(Move);
- end;
- else
- if (ChoiceSP = 0) then
- Exit; // error
- dec(ChoiceSP);
- with ChoiceStack[ChoiceSP] do begin
- i := chInx;
- Move := succ(chMove);
- State := chState;
- end;
- end;{Move case}
- end;
- ScanInteger :
- begin
- case Move of
- 0 :
- begin
- if (Ch in Digits) then
- inc(i)
- else
- inc(Move);
- end;
- else
- if (ChoiceSP = 0) then
- Exit; // error
- dec(ChoiceSP);
- with ChoiceStack[ChoiceSP] do begin
- i := chInx;
- Move := succ(chMove);
- State := chState;
- end;
- end;{Move case}
- end;
- ScanLeadDigits :
- begin
- case Move of
- 0 :
- begin
- if (Ch in Digits) then
- inc(i)
- else
- inc(Move);
- end;
- 1 :
- begin
- if (Ch = DecimalSeparator) then begin
- with ChoiceStack[ChoiceSP] do begin
- chInx := i;
- chMove := Move;
- chState := State;
- end;
- inc(ChoiceSP);
- State := ScannedDecPoint;
- Move := 0;
- inc(i);
- end
- else
- inc(Move);
- end;
- else
- if (ChoiceSP = 0) then
- Exit; // error
- dec(ChoiceSP);
- with ChoiceStack[ChoiceSP] do begin
- i := chInx;
- Move := succ(chMove);
- State := chState;
- end;
- end;{Move case}
- end;
- ScannedDecPoint :
- begin
- case Move of
- 0 :
- begin
- if (Ch in Digits) then
- inc(i)
- else
- inc(Move);
- end;
- else
- if (ChoiceSP = 0) then
- Exit; // error
- dec(ChoiceSP);
- with ChoiceStack[ChoiceSP] do begin
- i := chInx;
- Move := succ(chMove);
- State := chState;
- end;
- end;{Move case}
- end;
- ScanLeadDecPoint :
- begin
- case Move of
- 0 :
- begin
- if (Ch in Digits) then begin
- with ChoiceStack[ChoiceSP] do begin
- chInx := i;
- chMove := Move;
- chState := State;
- end;
- inc(ChoiceSP);
- State := ScanDecimalDigits;
- Move := 0;
- inc(i);
- end
- else
- inc(Move);
- end;
- else
- if (ChoiceSP = 0) then
- Exit; // error
- dec(ChoiceSP);
- with ChoiceStack[ChoiceSP] do begin
- i := chInx;
- Move := succ(chMove);
- State := chState;
- end;
- end;{Move case}
- end;
- ScanDecimalDigits :
- begin
- case Move of
- 0 :
- begin
- if (Ch in Digits) then
- inc(i)
- else
- inc(Move);
- end;
- else
- if (ChoiceSP = 0) then
- Exit; // error
- dec(ChoiceSP);
- with ChoiceStack[ChoiceSP] do begin
- i := chInx;
- Move := succ(chMove);
- State := chState;
- end;
- end;{Move case}
- end;
- end;{case}
- end;
- {if we reach this point, the number is valid if we're in a
- terminating state}
- if (State = ScanInteger) or
- (State = ScannedDecPoint) or
- (State = ScanDecimalDigits) then
- Result := true;
- end;
-
- var
- S : string;
-
- begin
- S := '+1';
- writeln(S, ':', NFAValidateNumber(S));
- S := '-12';
- writeln(S, ':', NFAValidateNumber(S));
- S := '12.';
- writeln(S, ':', NFAValidateNumber(S));
- S := '+12.3';
- writeln(S, ':', NFAValidateNumber(S));
- S := '-.1234';
- writeln(S, ':', NFAValidateNumber(S));
- readln;
- end.
-